#pragma once

#include<iostream>
#include<queue>
#include<pthread.h>
using namespace std;

template <class T>
class BlockQueue
{
    static const int defalutnum=1;
public:
    BlockQueue(int maxcp=defalutnum):maxcp_(maxcp)
    {
        pthread_mutex_init(&mutex_,nullptr);
        pthread_cond_init(&c_cond,nullptr);
        pthread_cond_init(&p_cond,nullptr);
        // low_water_=maxcp_/3;
        // high_water_=(maxcp_*2)/3;
    }
    T pop() 
    {
        //消费
        pthread_mutex_lock(&mutex_);
        while(q_.size()==0)
        {
            //如果线程wait时，被误唤醒了呢？   ---伪唤醒
            pthread_cond_wait(&c_cond,&mutex_);   //调用时会自动释放锁，唤醒后会重新获取锁
        }
        T out=q_.front();
        q_.pop();
        // if(q_.size()<low_water_) pthread_cond_signal(&p_cond);    //同理，消费者消费商品也可以保证商品数量不会达到上限
        pthread_cond_signal(&p_cond);    //ptread_cond_broadcast
        pthread_mutex_unlock(&mutex_);
        return out;
    }
    void push(const T &in)
    {
        //生产，这是一个阻塞队列，所以并不是想生产就能生产，要先确保生产条件满足
        pthread_mutex_lock(&mutex_);
        while(q_.size()==maxcp_)
        {
            //如果线程wait时，被误唤醒了呢？   ---伪唤醒
            pthread_cond_wait(&p_cond,&mutex_);    //进入等待队列，进入阻塞状态，同时把锁释放
        }
        q_.push(in);
        // if(q_.size()>high_water_)   pthread_cond_signal(&c_cond);     
        //生产者可以唤醒消费者的等待队列，因为生产者生产出一个商品就可以保证商品数量不为0
        pthread_cond_signal(&c_cond);        //
        pthread_mutex_unlock(&mutex_);
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&mutex_);
        pthread_cond_destroy(&c_cond);
        pthread_cond_destroy(&p_cond);
    }
private:
    queue<T> q_;        //共享资源
    int maxcp_;        //队列的极大值
    pthread_mutex_t mutex_;
    pthread_cond_t c_cond;
    pthread_cond_t p_cond;

    // int low_water_;
    // int high_water_;
};